using System;
using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using Locator.Silverlight.Client.Models.ViewModels.Elements;
using GalaSoft.MvvmLight.Messaging;
using GalaSoft.MvvmLight.Command;
using System.Collections.Generic;
using System.Windows;
using Locator.Silverlight.Client.Models.StoresServiceReference;
using System.Linq;

namespace Locator.Silverlight.Client.Models.ViewModels.Screens
{
    public class ManageStoresViewModel : ViewModelBase
    {
        private readonly IStoreModel storeModel;

        public ManageStoresViewModel()
            : this(new StoreModel())
        {

        }

        /// <summary>
        /// Initializes a new instance of the ManageStoresViewModel class.
        /// </summary>
        /// <param name="storeModel"></param>
        public ManageStoresViewModel(IStoreModel storeModel)
        {
            this.storeModel = storeModel;

#if DEBUG
            if (IsInDesignMode)
            {
                //this.UserStores = new ObservableCollection<StoreViewModel>() { 
                //    new StoreViewModel(new Store() { ID = 123, City = "Toronto", StreetAddress = "123 Fake St.", Latitude = 43.0M, Longitude = -79.0M }),
                //    new StoreViewModel(new Store() { ID = 124, City = "Oakville", StreetAddress = "2280 River Oaks", Latitude = 43.5M, Longitude = -79.1M })
                //};

                //for (int i = 0; i < 20; i++)
                //{
                //    this.UserStores.Add(new StoreViewModel(new Store() { ID = i, City = "Toronto", StreetAddress = i + " Some Street", Latitude = 43M + i / 10, Longitude = -79M - i / 10 }));
                //}

                StoreViewModel newStoreViewModel1 = new StoreViewModel()
                {
                    Id = 123,
                    Latitude = 43.0M,
                    Longitude = -79.0M
                };

                newStoreViewModel1.SetAddress("123 Fake St.", "Toronto");

                StoreViewModel newStoreViewModel2 = new StoreViewModel()
                {
                    Id = 124,
                    Latitude = 43.5M,
                    Longitude = -79.1M
                };

                newStoreViewModel2.SetAddress("2280 River Oaks", "Oakville");

                this.SearchResults = new ObservableCollection<UserStoreViewModel>() 
                { 
                    new UserStoreViewModel(newStoreViewModel1) 
                    { 
                        UsedByUser = true, 
                        Index = 1 
                    },

                    new UserStoreViewModel(newStoreViewModel2)
                    { 
                        UsedByUser = true, 
                        Index = 2 
                    }
                };

                for (int i = 0; i < 20; i++)
                {
                    StoreViewModel newStoreViewModel = new StoreViewModel()
                    {
                        Id = i,
                        Latitude = 43.0M + i / 10,
                        Longitude = -79.0M - i / 10
                    };

                    newStoreViewModel.SetAddress(i + " Fake St.", "City " + i);
                    this.SearchResults.Add(new UserStoreViewModel(newStoreViewModel)
                    {
                        UsedByUser = i % 2 == 0,
                        Index = i + 3
                    });
                }
            }
#endif

            this.AddStoreCommand = new RelayCommand<UserStoreViewModel>((store) => this.AddStore(store));
            this.RemoveStoreCommand = new RelayCommand<StoreViewModel>((store) => this.RemoveStore(store));
            this.FindStoresCommand = new RelayCommand<string>((cityName) => this.FindStores(cityName));
            this.FindStoresByPostalCodeCommand = new RelayCommand(() => this.FindStoresByPostalCode());
            this.FindStoresByPersonalLocationCommand = new RelayCommand<PersonalLocationViewModel>((personalLocation) => this.FindStoresByPersonalLocation(personalLocation));
            this.SearchRadiusItems = new List<int>() { 5, 10, 15, 20, 2000 };
            this.SearchPersonalLocationRadius = this.SearchRadiusItems[0];
            this.SearchRadius = this.SearchRadiusItems[0];

            if (!IsInDesignMode)
            {
                this.SearchResults = new ObservableCollection<UserStoreViewModel>();
                this.PersonalLocations = new ObservableCollection<PersonalLocationViewModel>();
                this.UserStores = new ObservableCollection<StoreViewModel>();
                this.Refresh();
            }
        }

        private void FindStoresByPersonalLocation(PersonalLocationViewModel personalLocation)
        {
            if (personalLocation != null && personalLocation.Latitude.HasValue && personalLocation.Longitude.HasValue)
            {
                this.storeModel.FindStoresByLatitudeAndLongitudeAsync(personalLocation.Latitude.Value, personalLocation.Longitude.Value, this.SearchPersonalLocationRadius, (stores, error) =>
                {
                    if (error != null)
                    {
                        // Display error, normally this would be done through a property
                        MessageBox.Show(error.Message);
                        return;
                    }

                    this.SearchResults.Clear();
                    foreach (StoreViewModel store in stores)
                    {
                        using (UserStoreViewModel userStore = new UserStoreViewModel(store))
                        {
                            var storeUsedByUser = this.UserStores.FirstOrDefault(s => s.Id == store.Id);
                            if (storeUsedByUser == null)
                            {
                                userStore.UsedByUser = false;
                            }
                            else
                            {
                                userStore.UsedByUser = true;
                            }

                            userStore.Index = this.SearchResults.Count + 1;
                            this.SearchResults.Add(userStore);
                        }
                    }
                });
            }
        }

        public const string PersonlLocationsPropertyName = "PersonalLocations";

        private ObservableCollection<PersonalLocationViewModel> personalLocations;

        public ObservableCollection<PersonalLocationViewModel> PersonalLocations
        {
            get { return this.personalLocations; }
            set
            {
                if (personalLocations == value)
                {
                    return;
                }

                personalLocations = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(PersonlLocationsPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="CurrentPersonlLocation" /> property's name.
        /// </summary>
        public const string CurrentPersonlLocationPropertyName = "CurrentPersonlLocation";

        private PersonalLocationViewModel currentPersonalLocation;

        /// <summary>
        /// Gets the CurrentPersonlLocation property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public PersonalLocationViewModel CurrentPersonlLocation
        {
            get
            {
                return currentPersonalLocation;
            }

            set
            {
                if (currentPersonalLocation == value)
                {
                    return;
                }

                var oldValue = currentPersonalLocation;
                currentPersonalLocation = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(CurrentPersonlLocationPropertyName);
            }
        }
        /// <summary>
        /// The <see cref="UserStores" /> property's name.
        /// </summary>
        public const string UserStoresPropertyName = "UserStores";

        private ObservableCollection<StoreViewModel> userStores;

        /// <summary>
        /// Gets the UserStores property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<StoreViewModel> UserStores
        {
            get { return userStores; }

            set
            {
                if (userStores == value)
                {
                    return;
                }

                userStores = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(UserStoresPropertyName);
            }
        }

        /// <summary>
        /// The <see cref="SearchResults" /> property's name.
        /// </summary>
        public static readonly string SearchResultsPropertyName = "SearchResults";

        private ObservableCollection<UserStoreViewModel> searchResults;

        /// <summary>
        /// Gets or sets the SearchResults property.
        /// TODO Update documentation:
        /// Changes to that property's value raise the PropertyChanged event. 
        /// This property's value is broadcasted by the Messenger's default instance when it changes.
        /// </summary>
        public ObservableCollection<UserStoreViewModel> SearchResults
        {
            get
            {
                return searchResults;
            }

            set
            {
                if (searchResults == value)
                {
                    return;
                }

                searchResults = value;

                // Update bindings, no broadcast
                RaisePropertyChanged(SearchResultsPropertyName);
            }
        }

        public RelayCommand<UserStoreViewModel> AddStoreCommand { get; private set; }

        public RelayCommand<StoreViewModel> RemoveStoreCommand { get; private set; }

        public RelayCommand<string> FindStoresCommand { get; private set; }

        public RelayCommand FindStoresByPostalCodeCommand { get; private set; }

        public RelayCommand<PersonalLocationViewModel> FindStoresByPersonalLocationCommand { get; private set; }

        public string CityNameToSearch { get; set; }

        public string PostalCode { get; set; }

        public int SearchRadius { get; set; }

        public List<int> SearchRadiusItems { get; set; }

        public int SearchPersonalLocationRadius { get; set; }

        private void Refresh()
        {
            this.storeModel.AllCitiesAsync((cities, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.AllCities = new ObservableCollection<CityViewModel>(cities);
            });

            //this.UserStores = ViewModelLocator.MainStatic.Stores;
            this.storeModel.GetStoresForCurrentUserAsync((stores, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.UserStores = new ObservableCollection<StoreViewModel>(stores);
            });

            this.storeModel.GetPersonalLocationsForCurrentUserAsync((locations, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.PersonalLocations.Clear();
                foreach (var location in locations)
                {
                    this.PersonalLocations.Add(location);
                }

                if (this.PersonalLocations.Count > 0)
                {
                    this.CurrentPersonlLocation = this.PersonalLocations[0];
                }
            });
        }

        private void AddStore(UserStoreViewModel store)
        {
            this.storeModel.AddStoreForCurrentUserAsync(store, (error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                store.UsedByUser = true;
                this.UserStores.Add(store.Store);
                //MessageBox.Show("Success");
            });
        }

        private void RemoveStore(StoreViewModel store)
        {
            this.storeModel.DeleteStoreForCurrentUserAsync(store, (error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }


                this.UserStores.Remove(store);
                foreach (UserStoreViewModel userStore in this.SearchResults)
                {
                    if (userStore.Store.Id == store.Id)
                    {
                        userStore.UsedByUser = false;
                    }
                }
                //MessageBox.Show("Success");
            });
        }

        private void FindStores(string cityName)
        {
            this.storeModel.FindStoresInCityAsync(cityName, (stores, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.SearchResults.Clear();
                foreach (StoreViewModel store in stores)
                {
                    using (UserStoreViewModel userStore = new UserStoreViewModel(store))
                    {
                        var storeUsedByUser = this.UserStores.FirstOrDefault(s => s.Id == store.Id);
                        if (storeUsedByUser == null)
                        {
                            userStore.UsedByUser = false;
                        }
                        else
                        {
                            userStore.UsedByUser = true;
                        }

                        userStore.Index = this.SearchResults.Count + 1;
                        this.SearchResults.Add(userStore);
                    }

                }
            });
        }

        private void FindStoresByPostalCode()
        {
            this.storeModel.FindStoresByPostalCodeAsync(this.PostalCode, this.SearchRadius, (stores, error) =>
            {
                if (error != null)
                {
                    // Display error, normally this would be done through a property
                    MessageBox.Show(error.Message);
                    return;
                }

                this.SearchResults.Clear();
                foreach (StoreViewModel store in stores)
                {
                    using (UserStoreViewModel userStore = new UserStoreViewModel(store))
                    {
                        var storeUsedByUser = this.UserStores.FirstOrDefault(s => s.Id == store.Id);
                        if (storeUsedByUser == null)
                        {
                            userStore.UsedByUser = false;
                        }
                        else
                        {
                            userStore.UsedByUser = true;
                        }

                        userStore.Index = this.SearchResults.Count + 1;
                        this.SearchResults.Add(userStore);
                    }
                }
            });
        }

        private ObservableCollection<CityViewModel> allCities;
        public ObservableCollection<CityViewModel> AllCities
        {
            get { return allCities; }
            set
            {
                if (allCities == value)
                    return;
                allCities = value;
                RaisePropertyChanged("AllCities");
            }
        }

        public CityViewModel CurrentCityForSearch { get; set; }
    }
}
